﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Xml;
using System.IO;

namespace VidoopSecure
{
    public class VoiceOtpService : Service
    {
        /// <summary>
        /// Creates an instance of a <see cref="VidoopSecure.VoiceOtpService" />.
        /// </summary>
        /// <param name="manager">The <see cref="VidoopSecure.VSManager" /> 
        /// for performing operations.</param>
        /// <param name="site">The <see cref="VidoopSecure.Site" /> associated
        /// with the service.</param>
        /// <param name="apiBase">The base URL for the VidoopSecure web service.</param>
        public VoiceOtpService(VSManager manager, Site site, string apiBase)
            : base(manager, site, apiBase)
        {
        }

        /// <summary>
        /// Creates an instance of <see cref="VidoopSecure.VoiceOtp" />.
        /// </summary>
        /// <param name="userId">User identifier.</param>
        /// <param name="phoneNumber">Phone number to which the call will be made.</param>
        /// <returns>An instance of <see cref="VidoopSecure.VoiceOtp" />.</returns>
        public VoiceOtp NewVoiceOtp(string userId, string phoneNumber)
        {
            string apiUrl = this.CreateRequestUrl("/customers/" + this.Site.CustomerId + "/sites/" + this.Site.SiteName + "/services/voiceotp");

            string credentials = this.Site.Username + Util.CREDENTIALS_SEPARATOR + this.Site.Password;

            Dictionary<string, string> parameters = new Dictionary<string, string>
            {
                { "user_id", userId },
                { "phone", phoneNumber }
            };
            
            HttpProxy proxy = this.Manager.ApiCall(apiUrl, "POST", parameters, credentials);

            if (proxy.StatusCode != (int)HttpStatus.Created)
                throw new VidoopSecureException(proxy.StatusCode, "Failed to create a new VoiceOTP service.");
            else
            {
                Stream stream = proxy.Response.GetResponseStream();

                VoiceOtp voiceotp = VoiceOtp.FromXml(stream);
                proxy.Close();
                return voiceotp;
            }
        }

        /// <summary>
        /// Get a <see cref="VidoopSecure.VoiceOtp" /> given an Id.
        /// </summary>
        /// <param name="voiceOtpId">The identifier of a <see cref="VidoopSecure.VoiceOtp" />.\
        /// </param>
        /// <returns>An instance of <see cref="VidoopSecure.VoiceOtp" />.</returns>
        public VoiceOtp GetVoiceOtp(string voiceOtpId)
        {
            string apiUrl = this.CreateRequestUrl("/customers/" + this.Site.CustomerId +
                "/sites/" + this.Site.SiteName + "/services/voiceotp/" + voiceOtpId);

            string credentials = this.Site.Username + Util.CREDENTIALS_SEPARATOR + this.Site.Password;

            HttpProxy proxy = this.Manager.ApiCall(apiUrl, "GET", null, credentials);
            if (proxy.StatusCode != (int)HttpStatus.OK)
            {
                int status = proxy.StatusCode;
                proxy.Close();
                throw new VidoopSecureException(status,
                    string.Format("Failed to get voiceotp transaction with Id = {0}", voiceOtpId));
            }
            else
            {
                VoiceOtp voiceOtp = VoiceOtp.FromXml(proxy.Response.GetResponseStream());
                proxy.Close();
                return voiceOtp;
            }
        }

        /// <summary>
        /// Validates that <paramref name="code"/> is the correct code for the
        /// <see cref="VidoopSecure.VoiceOtp" /> identified by 
        /// <paramref name="voiceOtpId"/>.
        /// </summary>
        /// <param name="voiceOtpId">A <see cref="VidoopSecure.VoiceOtp" /> 
        /// identifier</param>
        /// <param name="code">The code to validate.</param>
        /// <returns>true if the <paramref name="code"/>is the correct code
        /// for the <see cref="VidoopSecure.VoiceOtp" /> identified by
        /// <paramref name="voiceOtpId" />.</returns>
        public bool ValidateVoiceOtp(string voiceOtpId, string code)
        {
            string apiUrl = this.CreateRequestUrl("/customers/" + this.Site.CustomerId +
                "/sites/" + this.Site.SiteName + "/services/voiceotp/" + voiceOtpId);

            string credentials = this.Site.Username + Util.CREDENTIALS_SEPARATOR + this.Site.Password;

            Dictionary<string, string> parameters = new Dictionary<string, string>
            {
                { "otp", code }
            };

            HttpProxy proxy = this.Manager.ApiCall(apiUrl, "POST", parameters, credentials);
            int status = proxy.StatusCode;

            switch (status)
            {
                case (int)HttpStatus.CannotRetry:
                    {
                        proxy.Close();
                        throw new VidoopSecureException(status,
                            "Authentication with this Voice OTP has already been successful and cannot be attempted again.");
                    }

                case (int)HttpStatus.Gone:
                    {
                        proxy.Close();
                        throw new VidoopSecureException(status, "This Voice OTP has expired.");
                    }

                case (int)HttpStatus.AuthenticationFailed:
                    {
                        proxy.Close();
                        throw new VidoopSecureException(status, "Authentication failed.");
                    }

                case (int)HttpStatus.OK:
                    {
                        proxy.Close();
                        break;
                    }

                default:
                    {
                        proxy.Close();
                        throw new VidoopSecureException(status, "Unexpected error");
                    }
            }

            return true;
        }
    }
}
